package net.hn.hnms.sys.system.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.convert.Convert;
import cn.hutool.core.lang.tree.Tree;
import cn.hutool.core.lang.tree.TreeUtil;
import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.RequiredArgsConstructor;
import net.hn.hnms.sys.common.core.constant.UserConstants;
import net.hn.hnms.sys.common.core.exception.ServiceException;
import net.hn.hnms.sys.common.core.utils.StringUtils;
import net.hn.hnms.sys.common.core.utils.TreeBuildUtils;
import net.hn.hnms.sys.common.satoken.utils.LoginHelper;
import net.hn.hnms.sys.system.api.domain.SysDept;
import net.hn.hnms.sys.system.api.domain.SysRole;
import net.hn.hnms.sys.system.api.domain.SysUser;
import net.hn.hnms.sys.system.api.domain.vo.SysDeptNameForCodeVO;
import net.hn.hnms.sys.system.domain.UserTableEntity;
import net.hn.hnms.sys.system.mapper.SysDeptMapper;
import net.hn.hnms.sys.system.mapper.SysRoleMapper;
import net.hn.hnms.sys.system.mapper.SysUserMapper;
import net.hn.hnms.sys.system.request.OneAccessUserReq;
import net.hn.hnms.sys.system.service.ISysDeptService;
import org.jetbrains.annotations.Contract;
import org.springframework.stereotype.Service;

import java.util.*;

/**
 * 部门管理 服务实现
 *
 * @author Lion Li
 */
@RequiredArgsConstructor
@Service
public class SysDeptServiceImpl extends ServiceImpl<SysDeptMapper,SysDept> implements ISysDeptService {

    private final SysDeptMapper baseMapper;
    private final SysRoleMapper roleMapper;
    private final SysUserMapper userMapper;

    /**
     * 查询部门管理数据
     *
     * @param dept 部门信息
     * @return 部门信息集合
     */
    @Override
    public List<SysDept> selectDeptList(SysDept dept) {
        LambdaQueryWrapper<SysDept> lqw = new LambdaQueryWrapper<>();
        lqw.eq(SysDept::getDelFlag, "0")
            .eq(ObjectUtil.isNotNull(dept.getDeptId()), SysDept::getDeptId, dept.getDeptId())
            .eq(ObjectUtil.isNotNull(dept.getParentId()), SysDept::getParentId, dept.getParentId())
            .like(StringUtils.isNotBlank(dept.getDeptName()), SysDept::getDeptName, dept.getDeptName())
            .eq(StringUtils.isNotBlank(dept.getStatus()), SysDept::getStatus, dept.getStatus())
            .orderByAsc(SysDept::getParentId)
            .orderByAsc(SysDept::getOrderNum);
        return baseMapper.selectDeptList(lqw);
    }

    @Override
    public List<SysDept> selectDeptOrgList(SysDept dept) {
        LambdaQueryWrapper<SysDept> lqw = new LambdaQueryWrapper<>();
        lqw.eq(SysDept::getDelFlag, "0")
                .eq(ObjectUtil.isNotNull(dept.getDeptId()), SysDept::getDeptId, dept.getDeptId())
                .eq(ObjectUtil.isNotNull(dept.getParentId()), SysDept::getParentId, dept.getParentId())
                .like(StringUtils.isNotBlank(dept.getDeptName()), SysDept::getDeptName, dept.getDeptName())
                .eq(StringUtils.isNotBlank(dept.getStatus()), SysDept::getStatus, dept.getStatus())
                .eq(StringUtils.isNotBlank(dept.getOrganizationCode()), SysDept::getOrganizationCode, dept.getOrganizationCode())
                .isNotNull(SysDept::getOrganizationCode)
                .orderByAsc(SysDept::getParentId)
                .orderByAsc(SysDept::getOrderNum);
        return baseMapper.selectDeptList(lqw);
    }
    /**
     * 构建前端所需要下拉树结构
     *
     * @param depts 部门列表
     * @return 下拉树结构列表
     */
    @Override
    public List<Tree<String>> buildDeptTreeSelect(List<SysDept> depts) {
        if (CollUtil.isEmpty(depts)) {
            return CollUtil.newArrayList();
        }
        return TreeBuildUtils.build(depts, (dept, tree) ->
            tree.setId(dept.getDeptId().toString())
                .setParentId(dept.getParentId().toString())
                .setName(dept.getDeptName())
                .setWeight(dept.getOrderNum()));
    }
    @Override
    public List<Tree<Integer>> buildDeptTreeSelectOrg(List<SysDept> depts) {
        if (CollUtil.isEmpty(depts)) {
            return CollUtil.newArrayList();
        }
        return  TreeUtil.build(depts,0, (dept, tree) ->
                        tree.setId(Math.toIntExact(dept.getDeptId()))
                                .setParentId(Math.toIntExact(dept.getParentId()))
                                .setName(dept.getDeptName())
                                .setWeight(dept.getOrganizationCode())
                );
//        return TreeBuildUtils.build(depts, (dept, tree) ->
//            tree.setId(dept.getDeptId())
//                .setParentId(dept.getParentId())
//                .setName(dept.getDeptName())
//                .setWeight(dept.getOrganizationCode()));
    }

    /**
     * 根据角色ID查询部门树信息
     *
     * @param roleId 角色ID
     * @return 选中部门列表
     */
    @Override
    public List<Long> selectDeptListByRoleId(Long roleId) {
        SysRole role = roleMapper.selectById(roleId);
        return baseMapper.selectDeptListByRoleId(roleId, role.getDeptCheckStrictly());
    }

    /**
     * 根据部门ID查询信息
     *
     * @param deptId 部门ID
     * @return 部门信息
     */
    @Override
    public SysDept selectDeptById(Long deptId) {
        return baseMapper.selectById(deptId);
    }

    /**
     * 根据ID查询所有子部门（正常状态）
     *
     * @param deptId 部门ID
     * @return 子部门数
     */
    @Override
    public long selectNormalChildrenDeptById(Long deptId) {
        return baseMapper.selectCount(new LambdaQueryWrapper<SysDept>()
            .eq(SysDept::getStatus, UserConstants.DEPT_NORMAL)
            .apply("find_in_set({0}, ancestors) <> 0", deptId));
    }

    /**
     * 是否存在子节点
     *
     * @param deptId 部门ID
     * @return 结果
     */
    @Override
    public boolean hasChildByDeptId(Long deptId) {
        return baseMapper.exists(new LambdaQueryWrapper<SysDept>()
            .eq(SysDept::getParentId, deptId));
    }

    /**
     * 查询部门是否存在用户
     *
     * @param deptId 部门ID
     * @return 结果 true 存在 false 不存在
     */
    @Override
    public boolean checkDeptExistUser(Long deptId) {
        return userMapper.exists(new LambdaQueryWrapper<SysUser>()
            .eq(SysUser::getDeptId, deptId));
    }

    /**
     * 校验部门名称是否唯一
     *
     * @param dept 部门信息
     * @return 结果
     */
    @Override
    public String checkDeptNameUnique(SysDept dept) {
        boolean exist = baseMapper.exists(new LambdaQueryWrapper<SysDept>()
            .eq(SysDept::getDeptName, dept.getDeptName())
            .eq(SysDept::getParentId, dept.getParentId())
            .ne(ObjectUtil.isNotNull(dept.getDeptId()), SysDept::getDeptId, dept.getDeptId()));
        if (exist) {
            return UserConstants.NOT_UNIQUE;
        }
        return UserConstants.UNIQUE;
    }

    /**
     * 校验部门是否有数据权限
     *
     * @param deptId 部门id
     */
    @Override
    public void checkDeptDataScope(Long deptId) {
        if (!LoginHelper.isAdmin()) {
            SysDept dept = new SysDept();
            dept.setDeptId(deptId);
            List<SysDept> depts = this.selectDeptList(dept);
            if (CollUtil.isEmpty(depts)) {
                throw new ServiceException("没有权限访问部门数据！");
            }
        }
    }

    /**
     * 新增保存部门信息
     *
     * @param dept 部门信息
     * @return 结果
     */
    @Override
    public int insertDept(SysDept dept) {
        SysDept info = baseMapper.selectById(dept.getParentId());
        // 如果父节点不为正常状态,则不允许新增子节点
        if (!UserConstants.DEPT_NORMAL.equals(info.getStatus())) {
            throw new ServiceException("部门停用，不允许新增");
        }
        dept.setAncestors(info.getAncestors() + "," + dept.getParentId());
        return baseMapper.insert(dept);
    }

    /**
     * 修改保存部门信息
     *
     * @param dept 部门信息
     * @return 结果
     */
    @Override
    public int updateDept(SysDept dept) {
        SysDept newParentDept = baseMapper.selectById(dept.getParentId());
        SysDept oldDept = baseMapper.selectById(dept.getDeptId());
        if (ObjectUtil.isNotNull(newParentDept) && ObjectUtil.isNotNull(oldDept)) {
            String newAncestors = newParentDept.getAncestors() + "," + newParentDept.getDeptId();
            String oldAncestors = oldDept.getAncestors();
            dept.setAncestors(newAncestors);
            updateDeptChildren(dept.getDeptId(), newAncestors, oldAncestors);
        }
        int result = baseMapper.updateById(dept);
        if (UserConstants.DEPT_NORMAL.equals(dept.getStatus()) && StringUtils.isNotEmpty(dept.getAncestors())
            && !StringUtils.equals(UserConstants.DEPT_NORMAL, dept.getAncestors())) {
            // 如果该部门是启用状态，则启用该部门的所有上级部门
            updateParentDeptStatusNormal(dept);
        }
        return result;
    }

    /**
     * 修改该部门的父级部门状态
     *
     * @param dept 当前部门
     */
    private void updateParentDeptStatusNormal(SysDept dept) {
        String ancestors = dept.getAncestors();
        Long[] deptIds = Convert.toLongArray(ancestors);
        baseMapper.update(null, new LambdaUpdateWrapper<SysDept>()
            .set(SysDept::getStatus, UserConstants.DEPT_NORMAL)
            .in(SysDept::getDeptId, Arrays.asList(deptIds)));
    }

    /**
     * 修改子元素关系
     *
     * @param deptId       被修改的部门ID
     * @param newAncestors 新的父ID集合
     * @param oldAncestors 旧的父ID集合
     */
    public void updateDeptChildren(Long deptId, String newAncestors, String oldAncestors) {
        List<SysDept> children = baseMapper.selectList(new LambdaQueryWrapper<SysDept>()
            .apply("find_in_set({0},ancestors) <> 0", deptId));
        List<SysDept> list = new ArrayList<>();
        for (SysDept child : children) {
            SysDept dept = new SysDept();
            dept.setDeptId(child.getDeptId());
            dept.setAncestors(child.getAncestors().replaceFirst(oldAncestors, newAncestors));
            list.add(dept);
        }
        if (list.size() > 0) {
            baseMapper.updateBatchById(list);
        }
    }

    /**
     * 删除部门管理信息
     *
     * @param deptId 部门ID
     * @return 结果
     */
    @Override
    public int deleteDeptById(Long deptId) {
        return baseMapper.deleteById(deptId);
    }

    @Override
    public List<SysDept> selectBatchIds(List<Long> deptIds) {
        return baseMapper.selectBatchIds(deptIds);
    }

    @Override
    public List<SysDeptNameForCodeVO> getDeptName() {
        List<Map<String,String>> list = baseMapper.getDeptName();

        List<SysDeptNameForCodeVO> sysDeptNameForCodeVOS = new ArrayList<>();
        for (Map<String,String> map:list){
            SysDeptNameForCodeVO sysDeptNameForCodeVO = new SysDeptNameForCodeVO();
            sysDeptNameForCodeVO.setDeptName(map.get("dept_name"));
            sysDeptNameForCodeVO.setOrganizationCode(map.get("organization_code"));
            sysDeptNameForCodeVOS.add(sysDeptNameForCodeVO);
        }
        return sysDeptNameForCodeVOS;
    }

    @Override
    public SysDeptNameForCodeVO getParentDeptName(String mineCode) {
        Map<String,String> map = baseMapper.getDeptNameByMineCode(mineCode);
        SysDeptNameForCodeVO sysDeptNameForCodeVO = new SysDeptNameForCodeVO();
        sysDeptNameForCodeVO.setDeptName(map.get("dept_name"));
        sysDeptNameForCodeVO.setOrganizationCode(map.get("organization_code"));
        return sysDeptNameForCodeVO;
    }

    @Override
    public List<SysDept> getDeptByOrganizationCode(String organizationCode) {
        SysDept selectOne = baseMapper.selectOne(
                new LambdaQueryWrapper<SysDept>().eq(SysDept::getOrganizationCode, organizationCode));
        List<SysDept> depts = baseMapper.selectList(new LambdaQueryWrapper<SysDept>()
                .eq(SysDept::getParentId, selectOne.getDeptId()));
        return depts;
    }


    @Override
    public Map<String, Object> getDeptAndUserColumnInfo(OneAccessUserReq req) {

        List<UserTableEntity> deptList = baseMapper.getColumnInfoByTableName("sys_dept");
        List<UserTableEntity> userList = baseMapper.getColumnInfoByTableName("sys_user");

        deptList.forEach(dept -> {
            dept.setType(mysqlToJava(dept.getType()));
        });

        userList.forEach(user -> {
            user.setType(mysqlToJava(user.getType()));
        });


        Map<String, Object> map = new LinkedHashMap<>();
        map.put("iamRequestId", req.getIamRequestId());
        map.put("account", userList);
        map.put("organization", deptList);
        return map;
    }

    @Contract(pure = true)
    public static String mysqlToJava(String mysqlType) {
        switch (mysqlType) {
            case "bigint":
                return "int";
            case "int":
                return "int";
            case "varchar":
                return "String";
            case "char":
                return "String";
            case "datetime":
                return "String"; // 或者使用 java.util.Date
            case "double":
                return "double";
            case "float":
                return "float";
            case "long":
                return "long";
            case "byte":
                return "byte";
            case "boolean":
                return "boolean";
            default:
                return mysqlType;
        }
    }
}
